<?php

namespace customtool;

/**
 * 工具类
 * @author Chen KeYan
 */
class Utils {
    
    /**
    * @brief 检测函数必传参数是否存在
    * @param $params array 关联数组 要检查的参数
    * @param array $mod array 索引数组 要检查的字段
    * @param array $fields array 索引数组 额外要检查参数的字段
    * @return bool
    * @throws Exception
    */
   static function checkParamsExists($params, $mod = [], $fields = []) {
       if (empty($params)) {
           // throw new \Exception(Error::ERROR_INVALID_PARAMETER_MSG . ',[checkParamsExists] the array of params is empty', Error::ERROR_INVALID_PARAMETER_CODE);
           $resArr = array(
                'code'  => false,
                'msg'   => '未传递参数',
            );
            return json_encode($resArr, 320);
       }
       
       $params = is_array($params) ? $params : [$params];

       if ($fields) {
           $fields = array_flip($fields);
           $params = array_merge($params, $fields);
       } 

       foreach ($mod as $mod_key => $mod_value) {
           if (!array_key_exists($mod_value, $params)) {
               // throw new \Exception(Error::ERROR_INVALID_PARAMETER_MSG . ',[checkParamsExists]' . json_encode($params) . ' do not have key field(' . $mod_value . ')', Error::ERROR_INVALID_PARAMETER_CODE);
               $resArr = array(
                    'code'  => false,
                    'msg'   => '缺少必传参数' . $mod_value,
                );
                return json_encode($resArr, 320);
           }
       }
       return true;
    }


    
    /**
    * 打印log日志
    * @param 文件名 第几行 日志内容
    */
    static function log($basename=null, $title=null, $msg=null) {
        //$msg = [2018-04-11 09:22:56]文件名：wxpay，第29行，[info]：日志信息
        $msg = '[' . date("Y-m-d H:i:s") . ']' . '控制器定位：'. $basename .'，' . $title . '，'.'[info]：' . $msg;

        // 日志文件名：日期.txt
        $path = ROOT_PATH . DS . 'public' . DS . 'logs' . DS . date("Ymd") . '.txt';
        file_put_contents($path, $msg . PHP_EOL, FILE_APPEND);
    }
    
    /**
     * 使用post的传输
     */
    static function curl($url, $data) {
        // 启动一个CURL会话
        $ch = curl_init();
        // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, 120);
        // 忽略证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        // 发送一个常规的POST请求。
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // http_build_query 生成 URL-encode 之后的请求字符串
        curl_setopt($ch, CURLOPT_HEADER, 0); // 是否需要头部信息（否）
        // 执行操作
        $result = curl_exec($ch);
        if($result) {
            curl_close($ch);
            // 将返回json转换为数组
            $arrResult = json_decode($result, true);
//            if(!is_array($arrResult)) {
//                $arrResult['errcode']=1;
//                $arrResult['msg']='服务器繁忙，请稍候重试';
//            }
        } else {
            $arrResult = curl_error($ch);
            curl_close($ch);
//            $arrResult['errcode']=1;
//            $arrResult['msg']='服务器繁忙，请稍候重试';
        }
        // 返回数据
        return json_encode($arrResult, 320); 
    }
    
    /**
     * 使用post的传输
     */
    static function curlRetStr($url, $data) {
        // 启动一个CURL会话
        $ch = curl_init();
        // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, 120);
        // 忽略证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        // 发送一个常规的POST请求。
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // http_build_query 生成 URL-encode 之后的请求字符串
        curl_setopt($ch, CURLOPT_HEADER, 0); // 是否需要头部信息（否）
        // 执行操作
        $result = curl_exec($ch);
        curl_close($ch);
        // 返回数据
        return $result; 
    }
    
    /**
     * 使用post的传输
     */
    static function curlHttps($url, $data) {
//        return json_encode($data, 320); 
        // 启动一个CURL会话
        $ch = curl_init();
        // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, 120);
        // 忽略证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        // 发送一个常规的POST请求。
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // http_build_query 生成 URL-encode 之后的请求字符串
        curl_setopt($ch, CURLOPT_HEADER, 0); // 是否需要头部信息（否）
        // 执行操作
        $result = curl_exec($ch);
        curl_close($ch);
        return json_encode($result, 320); 
    }
    
    /**
     * object转Array
     */
    static function objectToArray($array) {
        if (is_object($array)) {
            $array = (array) $array;
        } if (is_array($array)) {
            foreach ($array as $key => $value) {
                $array[$key] = self::objectToArray($value);
            }
        }
        return $array;
    }
    /**
     * 获取客户端POST过来的json数据
     * @return json Object
     */
    static function jsonObjectGet()
    {
        $rawInput = fopen('php://input', 'r');
        $jsonStr = stream_get_contents($rawInput);
        fclose($rawInput);
        return json_decode($jsonStr);
    }
    
    /**
     * 获取加密序列号
     * @return json Object
     */
    static function getSnEncript($sn, $erTime)
    {
        return strtoupper(md5($sn . md5(sha1($erTime))));
    }

    /**
     * 获取linux系统的启动时长以ms单位返回
     * @return int (单位ms)
     */
    static function getLinuxUptimeMs() 
    {
        $uptime = exec('uptime -s');
        if($uptime == null) {
            return 0;
        }
        
        $dt = new DateTime($uptime);
        $nowTimeMs = (int)(microtime(true) * 1000);
        $upTimeMs = (int)($dt->getTimestamp() * 1000);
        if($upTimeMs < $nowTimeMs) {
            return ($nowTimeMs - $upTimeMs);
        }

        return 0;
    }
    
    /**
     * 获取当前时间以ms单位返回
     * @return type
     */
    static function getNowTimeMs()
    {
        return (int)(microtime(true) * 1000);
    }


    /**
     * 解析命令中的最大值最小值
     * @param type $cmd
     * @param type $wMin
     * @param type $wMax
     * @param type $cMin
     * @param type $cMax
     * @return int　(０＝没有报警参数，１＝只有一级报警参数，２＝有两级报警参数)
     */
    static function parseCmdParams($cmd, &$wMin, &$wMax, &$cMin, &$cMax)
    {
        $level = 0;
        $params = explode("!", $cmd);
        if(count($params) == 2) {
            $res = sscanf($params[1], "%f,%f", $wMin, $wMax);
            if($res > 0) {
                $level = 1;
            }
        } else if(count($params) == 3) {
            $res1 = sscanf($params[1], "%f,%f", $wMin, $wMax);
            $res2 = sscanf($params[2], "%f,%f", $cMin, $cMax);
            if($res1 > 0 && $res2 > 0) {
                $level = 2;
            } else if($res1 > 0 && $res2 <= 0) {
                $level = 1;//只有一级参数
            }
        }
        
        return $level;
    }
    
    /**
     * Ajax以json格式响应
     * @param type $msg
     * @param type $status
     * @param type $code
     * @param type $data
     */
    static function ajaxResponseJson($msg = '', $status = true, $code = '', $data = array()) {
        $obj = array(
            'msg' => $msg,
            'status' => $status
        );
        
        if(!empty($code)) {
            $obj['code'] = $code;
        }
        
        if(is_array($data) && count($data) > 0) {
            $obj['data'] = $data;
        }
        
        self::ajaxReturn($obj);
    }
    
    /**
     * Ajax以xml格式响应
     * @param type $msg
     * @param type $status
     * @param type $code
     * @param type $data
     */
    static function ajaxResponseXml($msg = '', $status = true, $code = '', $data = array()) {
        $obj = array(
            'msg' => $msg,
            'status' => $status
        );
        
        if(!empty($code)) {
            $obj['code'] = $code;
        }
        
        if(is_array($data) && count($data) > 0) {
            $obj['data'] = $data;
        }
        
        self::ajaxReturn($obj, 'xml');
    }
    
    /**
     * Ajax返回
     * @param type $obj
     * @param type $type    默认json格式,可选xml格式
     * @param type $xmlRoot xml格式的主节点
     */
    static function ajaxReturn($obj, $type='json', $xmlRoot = 'root')
    {
        header('Cache-Control: no-store');
        header('Pragma: no-cache');
        switch($type) {
            case 'xml':
                $xml = self::array2XML($obj, $xmlRoot);
                header('Content-Type:text/xml; charset="utf-8"');
                echo $xml;
                exit(0);
                break;
            default :
                //默认JSON格式返回
                $json = json_encode($obj);
                header('Content-type: application/json; charset="utf-8"');
                echo $json;
                exit(0);
                break;
        }
    }
    
    /**
     * 设置404头并退出
     */
    static function notFound404() {
        header("HTTP/1.1 404 Not Found");
        die();
    }

    /**
     * 数组转XML字符串
     * @param type $arr
     * @param type $root_element
     * @param type $version
     * @param type $encoding
     * @return type
     */
    static function array2XML($arr, $root_element = 'root', $version = "1.0", $encoding = "UTF-8") {
        $xml = new SimpleXMLElement("<?xml version=\"{$version}\" encoding=\"{$encoding}\" ?><{$root_element}></{$root_element}>");
        $f = create_function('$f,$c,$a', '
            foreach($a as $k=>$v) {
                if(is_array($v)) {
                    $ch=$c->addChild($k);
                    $f($f,$ch,$v);
                } else {
                    $c->addChild($k,$v);
                }
            }');
        $f($f, $xml, $arr);
        return $xml->asXML();
    }

    /**
     * 前缀检查方法
     * @param type $haystack
     * @param type $needle
     * @return type
     */
    static function startsWith($haystack, $needle) {
        return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE;
    }
    
    /**
     * 后缀检查方法
     * @param type $haystack
     * @param type $needle
     * @return type
     */
    static function endsWith($haystack, $needle) {
        return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
    }

    /**
     * 提取字符串中的数字
     * @param type $src
     * @return string
     */
    static function getNumByStr($src = '') {
        $result = '';
        $str = trim($src);
        if (empty($str)) {
            return $result;
        }
        
        for ($i = 0; $i < strlen($str); $i++) {
            if (is_numeric($str[$i])) {
                $result .= $str[$i];
            }
        }
        return $result;
    }
    
    /**
     * 获取浏览器信息函数
     * @author Jim
     */
    static function getBrowser() {
        $userAgent = $_SERVER['HTTP_USER_AGENT'];
        $bname = 'Unknown';
        $platform = 'Unknown';
        $version = "";

        //First get the platform?
        if (preg_match('/linux/i', $userAgent)) {
            $platform = 'linux';
        } elseif (preg_match('/macintosh|mac os x/i', $userAgent)) {
            $platform = 'mac';
        } elseif (preg_match('/windows|win32/i', $userAgent)) {
            $platform = 'windows';
        }

        // Next get the name of the useragent yes seperately and for good reason
        if (preg_match('/MSIE/i', $userAgent) && !preg_match('/Opera/i', $userAgent)) {
            $bname = 'Internet Explorer';
            $ub = "MSIE";
        } elseif (preg_match('/Firefox/i', $userAgent)) {
            $bname = 'Mozilla Firefox';
            $ub = "Firefox";
        } elseif (preg_match('/Chrome/i', $userAgent)) {
            $bname = 'Google Chrome';
            $ub = "Chrome";
        } elseif (preg_match('/Safari/i', $userAgent)) {
            $bname = 'Apple Safari';
            $ub = "Safari";
        } elseif (preg_match('/Opera/i', $userAgent)) {
            $bname = 'Opera';
            $ub = "Opera";
        } elseif (preg_match('/Netscape/i', $userAgent)) {
            $bname = 'Netscape';
            $ub = "Netscape";
        }

        // finally get the correct version number
        $known = array('Version', $ub, 'other');
        $pattern = '#(?<browser>' . join('|', $known) .
                ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
        if (!preg_match_all($pattern, $userAgent, $matches)) {
            // we have no matching number just continue
        }

        // see how many we have
        $i = count($matches['browser']);
        if ($i != 1) {
            //we will have two since we are not using 'other' argument yet
            //see if version is before or after the name
            if (strripos($userAgent, "Version") < strripos($userAgent, $ub)) {
                $version = $matches['version'][0];
            } else {
                $version = $matches['version'][1];
            }
        } else {
            $version = $matches['version'][0];
        }

        // check if we have a number
        if ($version == null || $version == "") {
            $version = "?";
        }

        return array(
            'ip' => self::getClientIp(),
            'name' => $bname,
            'version' => $version,
            'platform' => $platform,
            'userAgent' => $userAgent,
        );
    }
    
    /**
     * 获取客户端IP地址
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @return mixed
     */
    static function getClientIp($type = 0) {
        $type = $type ? 1 : 0;
        static $ip = NULL;
        if ($ip !== NULL) {
            return $ip[$type];
        }
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos = array_search('unknown', $arr);
            if (false !== $pos)
                unset($arr[$pos]);
            $ip = trim($arr[0]);
        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u", ip2long($ip));
        $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }
    
    /**
     * 检查是否ajax请求
     * @return boolean
     */
    static function isAjaxRequest() {
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
            return true;
        }
        
        return false;
    }
}
